#include <func.h>
/*
    生产者和消费者问题
*/
typedef struct {
    int tickets;
    pthread_mutex_t mutex;
    pthread_cond_t cond;
} data_t;

// 消费者1
void *window1(void *p)
{
    data_t *d = (data_t *)p;
    while (1)
    {
        // 加锁
        pthread_mutex_lock(&d->mutex);
        if (d->tickets > 0)
        {
            // 卖票
            printf("window1 sale ticket %d\n", d->tickets --);
            if (d->tickets == 0)
            {
                // 唤醒生产者
                pthread_cond_signal(&d->cond); 
            }
            // 解锁
            pthread_mutex_unlock(&d->mutex);
        } 
        else 
        {
            pthread_mutex_unlock(&d->mutex);
            break;
        }
        usleep(100);
    }
}

// 消费者2
void *window2(void *p)
{
    data_t *d = (data_t *)p;
    while (1)
    {
        // 加锁
        pthread_mutex_lock(&d->mutex);
        if (d->tickets > 0)
        {
            // 卖票
            printf("window2 sale ticket %d\n", d->tickets);
            d->tickets --;

            if (d->tickets == 0)
            {
                // 唤醒生产者
                pthread_cond_signal(&d->cond);
            }
            // 解锁
            pthread_mutex_unlock(&d->mutex);
        } 
        else 
        {
            pthread_mutex_unlock(&d->mutex);
            break;
        }
        usleep(100);
    }
}

// 生产者
void *set_tickets(void *p)
{
    data_t *d = (data_t *)p;
    while (1)
    {
        // 加锁
        pthread_mutex_lock(&d->mutex);

        // 等待
        if (d->tickets > 0)
            pthread_cond_wait(&d->cond, &d->mutex); // 等待时锁会解开
        
        // 生产
        d->tickets = 20;
        // 解锁
        pthread_mutex_unlock(&d->mutex);
    }
}

int main()
{
    pthread_t pthid[3];
    data_t d;
    d.tickets = 20;
    int ret;

    ret = pthread_mutex_init(&d.mutex, NULL);
    THREAD_ERR_CHECK(ret, "pthread_mutex_init");

    ret = pthread_cond_init(&d.cond, NULL);
    THREAD_ERR_CHECK(ret, "pthread_cond_init");

    ret = pthread_create(&pthid[0], NULL, window1, (void *)&d);
    THREAD_ERR_CHECK(ret, "pthread_create");
    ret = pthread_create(&pthid[1], NULL, window2, (void *)&d);
    THREAD_ERR_CHECK(ret, "pthread_create");
    ret = pthread_create(&pthid[2], NULL, set_tickets, (void *)&d);
    THREAD_ERR_CHECK(ret, "pthread_create");
        

    ret = pthread_join(pthid[0], NULL);
    THREAD_ERR_CHECK(ret, "pthread_join");
    ret = pthread_join(pthid[1], NULL);
    THREAD_ERR_CHECK(ret, "pthread_join");
    ret = pthread_join(pthid[2], NULL);
    THREAD_ERR_CHECK(ret, "pthread_join");

    ret = pthread_mutex_destroy(&d.mutex);
    THREAD_ERR_CHECK(ret, "pthread_mutex_destroy");
    ret = pthread_cond_destroy(&d.cond);
    THREAD_ERR_CHECK(ret, "pthread_cond_destroy");

    return 0;
}